""" dbi realizes the interface of interaction with a database
"""

import psycopg2
import logging
from twisted.internet import reactor


class dbi:
    """dbi realizes the interface of interaction with a database """
    def __init__(self, **kwargs):
        """ Constructor -- create the db connection. """
        
        logging.basicConfig()
        self.log = logging.getLogger('dbi')

        self.param = {}
        self.param['dsn'] = kwargs.get('dsn', '')
        self.param['test_period'] = kwargs.get('test_period', None)
        self.param['reconnect_handler'] = kwargs.get('reconnect_handler', None)
        self.param['disconnect_handler'] = kwargs.get('disconnect_handler', None)

        try:
            self.log.debug("dsn = %s", self.param['dsn'])
            self.log.debug("test period = %s", self.param['test_period'])
            # paramstyle = 'pystyle'
            self.connection = psycopg2.connect(self.param['dsn'])
            self.cursor = self.connection.cursor()
            self.connection_request = False
        except psycopg2.DatabaseError, x:
            self.connection_request = True
            self.log.error('%s', x)
        except:
            self.connection_request = True
            self.log.error('unknown error')
        if self.param['test_period']:
            reactor.callLater(self.param['test_period'], self.test_connection)

    def __del__(self):
        """ Destructor -- close the db connection."""
        self.connection.close()


    def test_connection(self):
        """ test_connection """
        try:
            test_connection = psycopg2.connect(self.param['dsn'])
            test_cursor = test_connection.cursor()
            if self.connection_request:
                self.connection = psycopg2.connect(self.param['dsn'])
                self.cursor = self.connection.cursor()
                if self.param['reconnect_handler']:
                    self.param['reconnect_handler']()
                self.connection_request = False
        except psycopg2.DatabaseError, x:
            if not self.connection_request:
                if self.param['disconnect_handler']:
                    self.param['disconnect_handler']()
                self.connection_request = True
            self.log.error('%s', x)
        except:
            if not self.connection_request:
                if self.param['disconnect_handler']:
                    self.param['disconnect_handler']()
                self.connection_request = True
            self.log.error('unknown error')
        reactor.callLater(self.param['test_period'], self.test_connection)

    def select(self, query, vars=None, async=0):
        """ select """
        try:
            self.cursor.execute(query, vars, async)
            self.connection.commit()
            return self.cursor.fetchall()
        except psycopg2.OperationalError, x:
            self.log.error('except OperationalError: %s - %s' % (query, x))
            return None
        except psycopg2.DatabaseError, x:
            try:
                self.connection.commit()
            except:
                pass
            self.log.error('except query: %s - %s' % (query, x))
            return None
        except:
            self.log.error('unknown error')
            return None

    def update(self, query, vars=None, async=0):
        """ update """
        try:
            self.cursor.execute(query, vars, async)
            self.connection.commit()
            return True
        except psycopg2.OperationalError, x:
            self.log.error('except OperationalError: %s - %s' % (query, x))
            return None
        except psycopg2.DatabaseError, x:
            try:
                self.connection.commit()
            except:
                pass
            self.log.error('except query: %s - %s' % (query, x))
            return None
        except:
            self.log.error('unknown error')
            return None

    def insert(self, query, vars=None, async=0):
        """ insert """
        try:
            self.cursor.execute(query, vars, async)
            self.connection.commit()
            return True
        except psycopg2.OperationalError, x:
            self.log.error('except OperationalError: %s - %s' % (query, x))
            return None
        except psycopg2.DatabaseError, x:
            try:
                self.connection.commit()
            except:
                pass
            self.log.error('except query: %s - %s' % (query, x))
            return None
        except:
            self.log.error('unknown error')
            return None
